﻿using System.Collections.Generic;
using System.Data;
using System.Text;

using SqlExecHelper.Cache;
using SqlExecHelper.Column;
using SqlExecHelper.Config;

namespace SqlExecHelper.Query
{
    internal class BatchQuery : ISqlBasic, IBatchQuery
    {
        private readonly IDAL _MyDAL = null;

        private readonly Batch.BatchSql _BatchExcel = null;
        public BatchQuery(string table, RunParam param, IDAL myDAL) : this(table, myDAL)
        {
            this._Name = SqlTools.GetTableName(table, "t", param);
        }
        private BatchQuery(string table, IDAL myDAL)
        {
            this._MyDAL = myDAL;
            this._BatchExcel = new Batch.BatchSql();
            this.TableName = table;
            this.Config = new SqlBatchConfig(table, "t");
        }
        private string _OrderBy = null;

        private string[] _Group = null;

        private ISqlWhere[] _Having = null;

        private int _TopNum = -1;
        protected readonly string _Name = "";
        public ISqlRunConfig Config { get; }

        public string TableName { get; }

        public SqlTableColumn[] Column
        {
            get => this._BatchExcel.Column;
            set => this._BatchExcel.Column = value;
        }

        public int RowCount => this._BatchExcel.RowCount;
        private ISqlWhere[] _Where = null;

        private SqlColumn[] _Column = null;
        private int _Skip = 0;
        private int _Size = 0;
        private bool _IsPaging = false;
        private bool _IsCount = true;

        private void _InitFoot(StringBuilder sql, List<IDataParameter> param)
        {
            if (this._Skip != 0)
            {
                SqlTools.InitPaging(sql, this._OrderBy, this._Skip, this._Size, this.Config, param);
            }
            else if (this._Group != null)
            {
                SqlTools.InitGroup(sql, this._OrderBy, this._Group, this._Having, this.Config, param);
            }
        }
        private string _GetSqlBody(List<IDataParameter> param)
        {
            StringBuilder main = new StringBuilder(128);
            main.AppendFormat(" from {0},{1} where ", this._Name, this._BatchExcel.TableName);
            SqlTools.InitWhereColumn(this._BatchExcel, main, this.Config);
            if (!this._Where.IsNull())
            {
                SqlTools.AppendWhere(main, this.Config, this._Where, param);
            }
            return main.ToString();
        }
        private string _GeneratePagingSql(List<IDataParameter> param)
        {
            string main = this._GetSqlBody(param);
            StringBuilder sql = new StringBuilder("select ", main.Length + 256);
            SqlTools.InitColumn(sql, this._Column, this.Config);
            if (this._IsCount)
            {
                return SqlTools.InitBatchPaging(sql, this._OrderBy, this._Skip, this._Size, this._Column[0].Name, this.Config, main, param);
            }
            else
            {
                sql.Append(main);
                SqlTools.InitPaging(sql, this._OrderBy, this._Skip, this._Size, this.Config, param);
            }
            return sql.ToString();
        }
        public StringBuilder GenerateSql(out IDataParameter[] param)
        {
            StringBuilder sql = this._BatchExcel.GenerateSql(out param);
            List<IDataParameter> list = new List<IDataParameter>();
            if (this._IsPaging)
            {
                sql.Append(this._GeneratePagingSql(list));
            }
            else
            {
                sql.Append("select ");
                SqlTools.InitHead(sql, this._TopNum);
                SqlTools.InitColumn(sql, this._Column, this.Config);
                sql.Append(this._GetSqlBody(list));
                this._InitFoot(sql, list);
            }
            param = param.Add(list);
            return sql;
        }

        public void AddRow(object[] datas)
        {
            this._BatchExcel.AddRow(datas);
        }
        #region 分组查询
        public T[] GroupColumn<T>(string group, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Column = new SqlColumn[] {
                                new SqlColumn(group),
                        };
            this._Group = new string[] { group };
            return SqlHelper.GetTable<T>(this, this._MyDAL);
        }
        public T[] GroupTable<T>(string group, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Column = ClassStructureCache.GetQueryColumn(typeof(T));
            this._Group = new string[] { group };
            return SqlHelper.GetTable<T>(this, this._MyDAL);
        }
        public T Group<T>(string group, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Column = ClassStructureCache.GetQueryColumn(typeof(T));
            this._Group = new string[] { group };
            return SqlHelper.GetRow<T>(this, this._MyDAL);
        }
        public T[] GroupTable<T>(string group, string sortBy, params ISqlWhere[] where)
        {
            this._Where = where;
            this._OrderBy = sortBy;
            this._Column = ClassStructureCache.GetQueryColumn(typeof(T));
            this._Group = new string[] { group };
            return SqlHelper.GetTable<T>(this, this._MyDAL);
        }
        public T Group<T>(string[] group, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Column = ClassStructureCache.GetQueryColumn(typeof(T));
            this._Group = group;
            return SqlHelper.GetRow<T>(this, this._MyDAL);
        }
        public T[] GroupTable<T>(string[] group, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Column = ClassStructureCache.GetQueryColumn(typeof(T));
            this._Group = group;
            return SqlHelper.GetTable<T>(this, this._MyDAL);
        }
        public T[] GroupTable<T>(string[] group, string sortBy, params ISqlWhere[] where)
        {
            this._Where = where;
            this._OrderBy = sortBy;
            this._Column = ClassStructureCache.GetQueryColumn(typeof(T));
            this._Group = group;
            return SqlHelper.GetTable<T>(this, this._MyDAL);
        }
        public T[] GroupColumn<T>(string group, int index, int size, out long count, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Column = new SqlColumn[] {
                                new SqlColumn(group),
                        };
            this._Group = new string[] { group };
            this._OrderBy = group;
            this._IsPaging = true;
            this._Skip = (index - 1) * size;
            this._Size = size;
            return SqlHelper.BatchQuery<T>(this, this._MyDAL, out count);
        }
        #endregion

        #region 分组查询(Group by having)

        public T[] GroupColumn<T>(string group, ISqlWhere[] having, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Having = having;
            this._Column = new SqlColumn[]
            {
                                new SqlColumn(group)
            };
            this._Group = new string[] { group };
            return SqlHelper.GetTable<T>(this, this._MyDAL);
        }
        public T[] GroupTable<T>(string group, ISqlWhere[] having, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Having = having;
            this._Column = ClassStructureCache.GetQueryColumn(typeof(T));
            this._Group = new string[] { group };
            return SqlHelper.GetTable<T>(this, this._MyDAL);
        }
        public T Group<T>(string group, ISqlWhere[] having, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Having = having;
            this._Column = ClassStructureCache.GetQueryColumn(typeof(T));
            this._Group = new string[] { group };
            return SqlHelper.GetRow<T>(this, this._MyDAL);
        }
        public T[] GroupTable<T>(string group, string orderBy, ISqlWhere[] having, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Having = having;
            this._OrderBy = orderBy;
            this._Column = ClassStructureCache.GetQueryColumn(typeof(T));
            this._Group = new string[] { group };
            return SqlHelper.GetTable<T>(this, this._MyDAL);
        }


        public T[] GroupTable<T>(string[] groups, ISqlWhere[] having, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Having = having;
            this._Column = ClassStructureCache.GetQueryColumn(typeof(T));
            this._Group = groups;
            return SqlHelper.GetTable<T>(this, this._MyDAL);
        }
        public T[] GroupTable<T>(string[] groups, string orderBy, ISqlWhere[] having, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Having = having;
            this._OrderBy = orderBy;
            this._Column = ClassStructureCache.GetQueryColumn(typeof(T));
            this._Group = groups;
            return SqlHelper.GetTable<T>(this, this._MyDAL);
        }
        #endregion

        #region 单列函数查询(count,sum等)
        public T ExecuteScalar<T>(string column, SqlFuncType funcType, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Column = new SqlColumn[]
            {
                                new SqlColumn(column, funcType)
            };
            return SqlHelper.ExecuteScalar<T>(this, this._MyDAL);
        }
        public T ExecuteScalar<T>(string column, string funcType, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Column = new SqlColumn[]
            {
                                new SqlColumn(column, null,funcType)
            };
            return SqlHelper.ExecuteScalar<T>(this, this._MyDAL);
        }
        #endregion

        #region 查询

    
        public T[] Query<T>(string column, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Column = new SqlColumn[]
            {
                new SqlColumn(column)
            };
            return SqlHelper.GetTable<T>(this, this._MyDAL);
        }
        public T[] Query<T>(params ISqlWhere[] where)
        {
            return this.QueryBySort<T>(null, where);
        }
        #endregion

        #region 排序查询
        public T[] QueryBySort<T>(string orderBy, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Column = ClassStructureCache.GetQueryColumn(typeof(T));
            this._OrderBy = orderBy;
            return SqlHelper.GetTable<T>(this, this._MyDAL);
        }
        #endregion

        #region 分页查询
        public T[] QueryByPaging<T>(string orderBy, int index, int size, out long count, params ISqlWhere[] where)
        {
            this._Where = where;
            this._Column = ClassStructureCache.GetQueryColumn(typeof(T));
            this._OrderBy = orderBy;
            this._IsPaging = true;
            this._Skip = (index - 1) * size;
            this._Size = size;
            return SqlHelper.BatchQuery<T>(this, this._MyDAL, out count);
        }

        public T[] QueryByPaging<T>(string orderBy, int index, int size, params ISqlWhere[] where)
        {
            this._Where = where;
            this._IsPaging = true;
            this._IsCount = false;
            this._Column = ClassStructureCache.GetQueryColumn(typeof(T));
            this._OrderBy = orderBy;
            this._Skip = (index - 1) * size;
            this._Size = size;
            return SqlHelper.GetTable<T>(this, this._MyDAL);
        }
        #endregion

        #region Top查询
        public T[] QueryByTop<T>(int topNum, params ISqlWhere[] where)
        {
            return this.QueryByTop<T>(topNum, null, where);
        }
        public T[] QueryByTop<T>(int topNum, string orderBy, params ISqlWhere[] where)
        {
            this._TopNum = topNum;
            this._Where = where;
            this._Column = ClassStructureCache.GetQueryColumn(typeof(T));
            this._OrderBy = orderBy;
            return SqlHelper.GetTable<T>(this, this._MyDAL);
        }
        #endregion
        public void Dispose()
        {

        }

      
    }
}
